package com.veetao.api.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.util.Assert;

import com.veetao.api.annotation.McpMethod;
import com.veetao.api.annotation.McpReq;
import com.veetao.api.model.ApiCommand;
import com.veetao.api.model.ApiFacade;
import com.veetao.api.model.CommandContext;

/**
 * CommandModel加载的工具类，已经改为支持无参接口和仅一个参数的接口。
 * 
 * @author Marshal(shuai.ma@renren-inc.com) Initial Created at 2013-10-29
 */
public class CommandModelUtils {


	private final static Map<String, Map<String, ApiCommand>> methodNameMap = new HashMap<String, Map<String, ApiCommand>>();

	public static ApiCommand getApiCommand1(String methodName, String version) {
		Map<String, ApiCommand> apis = methodNameMap.get(methodName);
		if (apis == null) {
			return null;
		}
		if (apis.size() == 1) {
			return apis.values().iterator().next();
		}
		if (version == null || version.isEmpty() || "1.0".equals(version)) {
			return apis.get("1.0");
		}
		
		if(apis.containsKey(version)) {
			return apis.get(version);
		}
		
		
		BigDecimal d = new BigDecimal(version);
		
		BigDecimal versionStepDecimal = new BigDecimal("0.1");
		while(d.floatValue() > 1.0) {
			// 向下找到第一个版本符合的方法
			d = d.subtract(versionStepDecimal);
			ApiCommand cmd = apis.get(d.floatValue()+"");
			if(cmd != null) {
				// 记住这个方法，避免每次都向下遍历查找
				apis.put(version, cmd);
				return cmd;
			}
		}
		
		return null;
	}

	/**
	 * 取方法级注解，支持无参接口和仅一个参数的接口。
	 * 
	 * @param o
	 * @return
	 */
	public static final List<ApiCommand> getMethodModelList(final ApiFacade o) {
		Class<?> clazz = o.getClass();
		List<ApiCommand> ls = new ArrayList<ApiCommand>();
		while (true) {
			Method[] ms = clazz.getDeclaredMethods();
			for (Method m : ms) {
				McpMethod mcpMethod = m.getAnnotation(McpMethod.class);
				if (mcpMethod == null) {
					continue;
				}
				if (methodNameMap.containsKey(mcpMethod.name())
						&& methodNameMap.get(mcpMethod.name()).containsKey(mcpMethod.ver())) {
					final String errorMsg = String.format("ApiFacade load error, %s exist %s[%s/%s], exit."//
							, clazz.getName()//
							, m.getName()//
							, mcpMethod.name()//
							, mcpMethod.ver()//
					);
					Assert.notNull(null, errorMsg);
					// continue;
				}
				Class<?>[] ps = m.getParameterTypes();
				if (ps.length < 1 || ps.length > 3 ) {
					continue;
				}
				if (ps[ps.length - 1] != CommandContext.class) {
					final String errorMsg = String
							.format("ApiFacade load error: 2nd params not CommandContext, %s %s[%s], exit."//
									, clazz.getName()//
									, m.getName()//
									, mcpMethod.name()//
					);
					Assert.notNull(null, errorMsg);
					continue;
				}
				// if (m.getReturnType() == void.class) continue;//现在支持void
				Class<?> req = null;// 无参时，此数据为null
				McpReq mcpReq = null;// 首参直接指定时，此值为非null
				Type mcpReqType = null;
				boolean withRawReqAndResp = false;
				if (ps.length == 2) {
					req = ps[0];
					Annotation[][] ass = m.getParameterAnnotations();
					if (ass.length > 0) {
						Annotation[] as = ass[0];
						for (Annotation a : as) {
							if (McpReq.class.isInstance(a)) {
								mcpReq = (McpReq) a;
								mcpReqType = m.getGenericParameterTypes()[0];
								break;
							}
						}
					}
				} else if(ps.length == 3 
						&& ps[0].getName().equals("javax.servlet.http.HttpServletRequest")
						&& ps[1].getName().equals("javax.servlet.http.HttpServletResponse")){
					withRawReqAndResp = true;
				}
				
				Class<?> resp = m.getReturnType();
				ApiCommand cmd = new ApiCommand(o, m);
				cmd.setReqClass(req);
				cmd.setRespClass(resp);
				cmd.setMcpMethod(mcpMethod);
				cmd.setWithRawReqAndResp(withRawReqAndResp);
				if (mcpReq != null && mcpReqType != null) {
					cmd.setMcpReq(mcpReq);
					cmd.setMcpReqType(mcpReqType);
				}
				
				ls.add(cmd);
				Map<String, ApiCommand> apis = methodNameMap.get(mcpMethod.name());
				if (apis == null) {
					apis = new HashMap<String, ApiCommand>();
					methodNameMap.put(mcpMethod.name(), apis);
				}
				apis.put(mcpMethod.ver(), cmd);
			}
			clazz = clazz.getSuperclass();
			if (clazz.getName().startsWith("java.")) {
				return ls;
			}
		}
	}
}
